<?php
/**
 * Created by laoyu.
 * User: hilaoyu@qq.com
 * Date: 2018/5/22
 * Time: 16:01
 */

namespace Hilaoyu\LaravelExtend;



use Hilaoyu\Utils\UtilAes;
use Hilaoyu\Utils\UtilArr;
use Hilaoyu\Utils\UtilAes as Encrypter;
use Hilaoyu\Utils\UtilHttp;
use Hilaoyu\Utils\UtilStr;
use Hilaoyu\Utils\UtilSupport;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;


class ComResponse
{


    protected $variables = [];
    protected $data = null;
    protected $errors = [];
    protected $debugs = [];
    protected $message = '';

    protected $headers = [];
    protected $cookies = [];
    protected $statusCode = 0;
    protected $status = true;
    protected $pager = null;
    protected $pager_need_build = false;
    protected $pager_in_data = false;
    protected $pager_template = '';


    /**
     * 刷新自己
     */
    public function refresh($key = '')
    {
        if (in_array($key, ['variables', 'errors', 'debugs', 'headers', 'cookies'])) {
            $this->{$key} = [];
        } else if ('status' == $key) {
            $this->status = true;
        } else if ('' != $key) {
            $this->{$key} = null;
        } else {
            $this->variables = [];
            $this->data = null;
            $this->errors = [];
            $this->debugs = [];

            $this->headers = [];
            $this->cookies = [];
            $this->statusCode = 0;
            $this->status = true;
            $this->pager = null;
        }

        return $this;
    }

    public function setPagerInData(bool $inData){
       $this->pager_in_data = $inData;
        return $this;
    }

    public function setStatusCode($statusCode = 0)
    {
        if (($statusCode = intval($statusCode)) > 0) {
            $this->statusCode = $statusCode;
        }
        return $this;
    }

    public function getStatusCode()
    {
        return $this->statusCode;
    }

    public function getStatus()
    {
        return $this->status;
    }


    public function getVariable($key = '', $default = null)
    {
        $key = trim($key);

        if ($key) {
            return data_get($this->variables, $key, $default);
        }


        return $this->variables;
    }

    public function getData($key = '', $default = null)
    {
        $key = trim($key);

        if ($key) {
            return data_get($this->data, $key, $default);
        }
        return $this->data;
    }

    public function getError($key = '', $default = null)
    {
        $key = trim($key);

        if ($key) {
            return data_get($this->errors, $key, $default);
        }
        return $this->errors;
    }

    /**
     * 数据赋值
     * @param * $variable 值
     * @param String $key 键，为空则覆盖所有已赋的值
     * @param \Hilaoyu\Utils\UtilAes $encrypter 加密器，如果传入则对当前值转json后加密
     * @return $this
     */
    public function with($variable, $key = null, UtilAes $encrypter = null)
    {

        if ($encrypter instanceof UtilAes) {
            try {
                $variable = $encrypter->encryptString(json_encode($variable, JSON_UNESCAPED_UNICODE));
            } catch (\Exception $e) {
                $variable = null;
            }
        }

        if (!empty($key) && is_string($key)) {
            $key = trim($key);
            $this->variables[$key] = $variable;
        } else {
            $this->data = $variable;
        }

        return $this;
    }

    /**
     * 赋值分页数据
     * @param $pager
     * @return $this
     */
    public function withPager($pager, $build = true, $pager_template = '')
    {
        /*$total = intval($total);
        if($total < 0){
            $total = 0;
        }

        $offset = intval($offset);
        if($offset < 0){
            $offset = 0;
        }

        $start = intval($start);
        if($start < 0){
            $start = 0;
        }

        $this->pager = [
            'start' => $start, // 起始位置
            'offset' => $offset, // 偏移量 （每次返回多少条）。这个应该是前端传过来的或不传默认的
            'total' => $total, //总数
        ];*/

        $this->pager = $pager;
        $this->pager_need_build = $build;
        $this->pager_template = $pager_template;

        return $this;

    }


    /**
     * 赋值错误信息
     * @param $errors
     * @param null $key
     * @return $this
     */
    public function withErrors($errors, $key = null)
    {

        if (!empty($key) && is_string($key)) {
            $errors = [$key => UtilArr::toString($errors)];
        }

        $errors = (array)$errors;


        foreach ($errors as $mk => $error) {
            if (is_string($mk) && !empty($mk)) {
                $this->errors[$mk] = Arr::get($this->errors, $mk, '') . ' ' . UtilArr::toString($error);
            } else {
                $this->errors[] = UtilArr::toString($error);
            }
        }


        return $this;
    }

    /**
     * 设置头信息 多条
     * @param array $headers
     * @return $this
     */
    public function withHeaders(array $headers = [])
    {

        foreach ($headers as $key => $value) {
            $this->withHeader($key, $value);
        }

        return $this;
    }

    public function withCookie($name = null, $value = null, $minutes = 0, $httpOnly = true, $raw = false)
    {
        $this->cookies[] = Cookie::create($name, $value, $minutes, '/', null, null, $httpOnly, $raw);
        //$this->cookies[] = func_get_args();

        return $this;
    }

    /**
     * 设置头信息 单条
     * @param $key
     * @param $values
     * @param bool $replace
     * @return $this
     */
    public function withHeader($key, $values, $replace = true)
    {
        if (true === $replace || !isset($this->headers[$key])) {
            $this->headers[$key] = [$values];
        } else {
            $this->headers[$key][] = $values;
        }

        return $this;
    }

    /**
     * 赋值调试信息
     * @param $var
     * @param null $key
     * @return $this
     */
    public function withDebug($var, $key = null)
    {

        if (is_string($key) && !empty($key)) {
            $this->debugs[$key] = $var;
        } else {
            $this->debugs[] = $var;
        }
        return $this;
    }

    /**
     * 成功
     * @param string $message
     * @param null $statusCode
     * @param null $data 如果传入则覆盖前面所有已赋值
     * @return $this
     */
    public function success($message = '', $statusCode = null, $data = null)
    {
        $this->status = true;

        if (!is_null($statusCode)) {
            $this->statusCode = $statusCode;
        }

        if (!is_null($data)) {
            //$data = (array) $data;
            $this->data = $data;
        }

        //empty($message) && $message = 'success';
        $this->message = $message;

        return $this;
    }

    /**
     * 失败
     * @param string $message
     * @param null $statusCode
     * @return $this
     */
    public function failed($message = '', $statusCode = null)
    {

        $this->status = false;

        if (!is_null($statusCode)) {
            $this->statusCode = $statusCode;
        }

        //empty($message) && $message = 'failed';
        $this->message = $message;

        return $this;
    }

    /**
     * 以json方式返回数据
     * @param null $data
     * @return \Illuminate\Http\JsonResponse
     */
    public function json($data=null){
        $pager = null;
        if(!empty($this->pager)){
            $pager = $this->buildPager()->toArray();
            $pager['data'] = [];
        }
        if ($this->pager_in_data){
            $this->with($pager,"pager");
        }
        if(is_null($data)){
            if(is_null($this->data) && !empty($this->variables)){
                $this->data = $this->variables;
                $this->variables = [];
            }
            $data = [
                'code' => $this->statusCode, //状态代码 ,以后用时定义
                'status' => $this->status, //是否成功 ，true|false
                'errors' => Arr::where($this->errors,function ($value){return !empty($value);}), //信息   数组
                'message' => $this->message,
                //'data' => is_null($this->data) ? $this->variables : $this->data, //业务数据
                'data' => $this->data, //业务数据
            ];

            $data = array_merge($this->variables,$data);

            /*if(($pager = $this->buildPager())){
                $data['pager'] = $this->pager;
                $data['pager_rend'] = $pager->render();
            }*/

            if($pager && !$this->pager_in_data){
                $data['pager'] = $pager;
            }
            if(!empty($this->debugs)){
                $data['debug'] = $this->debugs;
            }



        }


        //ob_clean();
        $response = response()->json($data);

        $this->setStatusCode(200);
        $response = $this->buildStandardResponse($response);


        return $response;

    }

    /**
     * 渲染模板返回
     * @param String $template 模板
     * @return $this|\Illuminate\Contracts\View\Factory|\Illuminate\View\View|mixed
     */
    public function view($template)
    {

        if (!Str::contains($template, '::') && $namespace = env('APP_ENV')) {
            if (view()->exists($namespace . '::' . $template)) {
                $template = $namespace . '::' . $template;
            }

        }
        $response = view($template, [], $this->errors);

        $response = $this->buildResponseData($response);
        $response = $this->buildStandardResponse($response);
        //$this->refresh();
        //dd($response);
        return $response;
    }


    public function viewRaw($content)
    {
        $response = $this->buildStandardResponse($content);
        //$this->refresh();
        //dd($response);
        return $response;
    }

    /**
     * 跳转
     * @param $uri
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|mixed
     */
    public function redirect($uri, $status = 302)
    {
        if (request()->expectsJson()) {
            $this->setStatusCode(20301);
            return $this->with($uri, 'redirect_url')->json();
        }
        $response = redirect($uri, $status)->withInput();
        $response = $this->buildResponseData($response);
        $response = $this->buildStandardResponse($response);
        //$this->refresh();
        return $response;
    }

    /**
     * 回到上一个页面
     * @return $this|\Illuminate\Contracts\View\Factory|\Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\View\View
     */
    public function back()
    {
        return $this->redirect(back()->getTargetUrl());
    }


    /**
     * 反向代理
     * @param $uri
     * @return void
     */
    public function reverseProxy($uri, $params = [], $method = "", $headers = [],$disposition="")
    {
        $ch = UtilHttp::Curl($uri, $params, $method, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
        curl_setopt($ch, CURLOPT_HEADER, false);

        $tempFile = \tmpfile();
        $tempFilePath = stream_get_meta_data($tempFile)['uri'];
        $response = new StreamedResponse();
        curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $headerLine) use ($response) {
            $hl = strlen($headerLine);
            $headerLine = trim($headerLine);
            if ($headerLine !== ''  && !Str::startsWith(Str::lower($headerLine),"set-cookie")) {
                $response->headers->set(Str::before($headerLine,":"),Str::after($headerLine,":"));
            }
            return $hl;
        });
        curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $data) use ($tempFile) {
            fwrite($tempFile, $data);
            return strlen($data);
        });

        // 执行 cURL 请求
        $rs = curl_exec($ch);

        $result_http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if (!$rs || !UtilStr::startsWith($result_http_code, '20')) {
            return $this->viewRaw("打开远程地址出错:" . $result_http_code);
        }
         $response->setCallback(function () use ($tempFile){
            if (is_resource($tempFile)) {
                rewind($tempFile);
                fpassthru($tempFile);
                fclose($tempFile);
            }
             return false;
        });
        $response->setStatusCode($result_http_code);
        if("" != $disposition){
            $response->headers->set('Content-Disposition', $disposition);
        }

        return $response;

    }

    /**
     * 构建返回携带的数据
     * @param $response
     * @return \Illuminate\Http\RedirectResponse | \Illuminate\View\View|\Illuminate\Contracts\View\Factory
     */
    protected function buildResponseData($response)
    {
        //$this->header('TestHeader','testaaaa');
        //$data = empty($this->data) ? $this->variables : $this->data;
        //dd($this->errors);
        $response->with($this->variables)
            ->with(['data' => $this->data])
            ->with('status', $this->status);


        if (!empty($this->errors)) {
            $response->withErrors($this->errors);
        }

        if (!empty($this->message)) {
            $response->with('message', $this->message);
        }


        if (!empty($this->debugs)) {
            $response->with('debug', $this->debugs);
        }


        if (($pager = $this->buildPager())) {
            $response->with('pager', $pager->render());
        }


        return $response;
    }

    /**
     * @param $response
     * @return \Illuminate\Http\Response
     */
    protected function buildStandardResponse($response)
    {


        if (!$response instanceof Response) {
            $response = response($response);
        }


        if ($this->statusCode > 0) {
            UtilSupport::tryQuiet(function () use (&$response) {
                $response = $response->setStatusCode($this->statusCode);
            });

        }

        if (!empty($this->headers)) {
            UtilSupport::tryQuiet(function () use (&$response) {
                $response = $response->withHeaders($this->headers);
            });

        }

        if (!empty($this->cookies)) {
            UtilSupport::tryQuiet(function () use (&$response) {
                foreach ($this->cookies as $cookie) {
                    call_user_func_array([$response, 'cookie'], [$cookie]);
                }
            });

        }

        return $response;
    }


    public function getPager()
    {
        return $this->pager;
    }

    public function buildPager()
    {
        if (!$this->pager_need_build) {
            return $this->pager;
        }
        $pager = null;
        if (!empty($this->pager)) {
            $template_name = $this->pager_template;
            if (!$template_name) {
                $template_name = "pagination";
            }

            $template = "LaravelExtend::" . $template_name;
            if ($namespace = env('APP_ENV')) {
                if (view()->exists($namespace . '::' . $template_name)) {
                    $template = $namespace . '::' . $template_name;
                }

            } else {
                if (view()->exists($template_name)) {
                    $template = $template_name;
                }
            }


            LengthAwarePaginator::defaultView($template);
            $pager = new LengthAwarePaginator(
                $this->getVariable('models', [])
                , $this->pager['total']
                , $this->pager['offset']
                , $this->pager['page']
                , [
                    'path' => '/' . request()->path(),
                    'pageName' => 'pager_page',
                    'query' => request()->query()
                ]
            );
            //dd($pager->render());


        }
        return $pager;
    }


}
